#ifndef TCPA_UTIL_H
#define TCPA_UTIL_H

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include "tcpa_monitor.h"
#include "tools_func.h"

static inline char *get_net_mode_str(net_mode_e mode)
{
    switch (mode) {
        case NET_MODE_NONE:
            return "none";
        case NET_MODE_ROUTE:
            return "route";
        case NET_MODE_NAT:
            return "nat";
        default:
            return "unknown";
    }
}

static inline int64_t call_start_tcp_sh(tcpa_cfg_t *cfg) 
{
    // 调用启动脚本
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s/start_tcp.sh %s %s %s %u %u %u %s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH, 
            cfg->vrf_name, cfg->local_ip_str, cfg->server_ip_str, cfg->server_port, cfg->listen_port, cfg->max_connect, get_net_mode_str(cfg->net_mode));
    return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline void call_stop_tcp_sh(uint32_t pid, char *vrf_name, char *server_ip_str) 
{
    // 调用停止脚本
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s/stop_tcp.sh %u %s %s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH, pid, vrf_name, server_ip_str);
    run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline int call_add_whitelist_rule_sh(rule_cfg_t *rule) 
{
    char cmd[1024] = {0};
    // add [vrfname] <src_ip:sport1-dst_ip:dport1-rcst_ip>"
    snprintf(cmd, sizeof(cmd), "%s/white_list.sh add %s %s:%u-%s:%u-%s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH,
            rule->vrf_name, rule->src_ip_str, rule->src_port, rule->dst_ip_str, rule->dst_port, rule->local_ip_str);
    return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline int call_del_whitelist_rule_sh(rule_cfg_t *rule) 
{
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s/white_list.sh del vrf %s %s:%u-%s:%u-%s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH,
            rule->vrf_name, rule->src_ip_str, rule->src_port, rule->dst_ip_str, rule->dst_port, rule->local_ip_str);
    return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline int call_del_whitelist_vrf_sh(char *vrfname) 
{
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s/white_list.sh del vrf %s all", TCP_ACCELERATION_CONTROL_SCRIPT_PATH, vrfname);
    return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline void call_clean_whitelist_sh(tcpa_monitor_t *monitor) 
{
    // clean tcpa whitelist = 白名单的vrf 需要与 加速配置的vrf 一致
    // rule_cfg_t *rule_cfg = NULL;
    // list_for_each_entry(rule_cfg, &monitor->rule_list, node) {
    //     call_del_whitelist_vrf_sh(rule_cfg->vrf_name);
    // }

    rule_cfg_t *rule_cfg = NULL, *tmp = NULL;
    list_for_each_entry_safe(rule_cfg, tmp, &monitor->rule_list, node) {
        if (call_del_whitelist_vrf_sh(rule_cfg->vrf_name) != 0) {
            TCPAM_LOG_ERROR("Failed to delete whitelist rule for VRF: %s", rule_cfg->vrf_name);
        }
    }

    return ;
}

// static inline int call_enable_whitelist_sh(char *vrfname) 
// {
//     char cmd[1024] = {0};
//     snprintf(cmd, sizeof(cmd), "%s/white_list.sh enable 0.0.0.0 %s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH, vrfname);
//     return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
// }

static inline int call_disable_whitelist_sh(char *vrfname) 
{
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s/white_list.sh disable 0.0.0.0 %s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH, vrfname);
    return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline int call_disable_nat(const char *rcst_ip_str, const char *vrfname) 
{
    char cmd[1024] = {0};
    snprintf(cmd, sizeof(cmd), "%s/white_list.sh disable_nat %s %s", TCP_ACCELERATION_CONTROL_SCRIPT_PATH, rcst_ip_str, vrfname);
    return run_shell_cmd(NULL, 0, cmd, PRINT_RUN_CMD_LOG);
}

static inline void clean_rule_cfg(rule_cfg_t *rule)
{
    memset(rule, 0, sizeof(rule_cfg_t));
}

static inline bool rule_cfg_is_exist(list_head_t *rule_list, rule_cfg_t *rule) 
{
    rule_cfg_t *pNode = NULL;
    list_for_each_entry(pNode, rule_list, node) {
        if (strcmp(pNode->src_ip_str, rule->src_ip_str) == 0 && pNode->src_port == rule->src_port &&    
            strcmp(pNode->dst_ip_str, rule->dst_ip_str) == 0 && pNode->dst_port == rule->dst_port &&
            strcmp(pNode->vrf_name, rule->vrf_name) == 0) {
            pNode->in_use = true;
            return true;
        }
    }
    return false;
}

static inline bool tcpa_is_running(tcpa_ctrl_t *tcpa_ctrl) 
{
    return tcpa_ctrl->tcpa_pid != 0;
}

static inline int pid_exists_from_td_tunnel_tcp(uint64_t pid)
{
    char terminal_output_buf[1024] = {0};
    char cmd[1024] = {0};
#ifdef TD_SYSTEM
    snprintf(cmd, sizeof(cmd), "ps -ef | grep -w %s | grep -v grep | awk -F' ' '{print $1}'", TCP_ACCELERATION_PROCESS_NAME);
#else
    snprintf(cmd, sizeof(cmd), "ps -ef | grep -w %s | grep -v grep | awk -F' ' '{print $2}'", TCP_ACCELERATION_PROCESS_NAME);
#endif
    if (run_shell_cmd(terminal_output_buf, sizeof(terminal_output_buf), cmd, NO_PRINT_RUN_CMD_LOG) < 0) {
        // PID does not exist
        return 0;
    }
    char ttt_pid_str_array[VRF_MAX_NUM][128] = {0};
    int pid_str_num = cut_str_for_keyword(ttt_pid_str_array, sizeof(ttt_pid_str_array), terminal_output_buf, strlen(terminal_output_buf), "\n");
    for (int i = 0; i < pid_str_num; i++) {
        uint64_t ttt_pid = atoll(ttt_pid_str_array[i]);
        // printf("pid_str[%d]:%s str to u64:%lu. need pid:%lu\n", i, ttt_pid_str_array[i], ttt_pid, pid);
        if (ttt_pid == pid) {
            return 1; // PID exists
        }
    }
    return 0; // PID does not exist
}

static inline int tcpa_pid_ctrl_util(tcpa_ctrl_t *ctrl) 
{
    int64_t pid = call_start_tcp_sh(&ctrl->tcpa_cfg);
    if (pid < 0) {
        ctrl->tcpa_pid = 0;
        return -1;
    }
    else {
        ctrl->tcpa_pid = pid;
    }
    return 0;
}

static inline void clean_tcpa_ctrl(tcpa_ctrl_t *ctrl)
{
    memset(ctrl, 0, sizeof(tcpa_ctrl_t));
}

static inline int stop_tcpa_util(tcpa_ctrl_t *ctrl)
{
    uint32_t need_kill_pid = ctrl->tcpa_pid;
    // 调用停止脚本
    if (need_kill_pid) {
        call_stop_tcp_sh(need_kill_pid, ctrl->tcpa_cfg.vrf_name, ctrl->tcpa_cfg.server_ip_str);
    }
    ctrl->tcpa_pid = 0;
    ctrl->tcpa_action_mask = 0;
    ctrl->tcpa_restart_cnt = 0;
    memset(&ctrl->backoff, 0, sizeof(ctrl->backoff));
    return 0;
}

// 异常状态校验
static inline bool tcpa_abnormal_status_check(tcpa_ctrl_t *ctrl, uint64_t abnormal_state_mask)
{
    bool ret = false;
    switch (abnormal_state_mask) {
        // 未设置server_ip
        case TCPA_ABNORMAL_STATUS_UNSET_SERVER_IP: {
            if (ctrl->tcpa_cfg.server_ip_str[0] == '\0') {
                if (!(ctrl->abnormal_state & TCPA_ABNORMAL_STATUS_UNSET_SERVER_IP)) {
                    TCPAM_LOG_ERROR("unset server_ip for %s", ctrl->tcpa_cfg.vrf_name);
                    ctrl->abnormal_state |= TCPA_ABNORMAL_STATUS_UNSET_SERVER_IP;
                }
                ret = true;
            }
            else if (ctrl->abnormal_state & TCPA_ABNORMAL_STATUS_UNSET_SERVER_IP) {
                ctrl->abnormal_state &= ~TCPA_ABNORMAL_STATUS_UNSET_SERVER_IP;
                TCPAM_LOG_INFO("set server_ip[%s] for %s", ctrl->tcpa_cfg.server_ip_str, ctrl->tcpa_cfg.vrf_name);
                ret = false;
            }
        }
        break;
        default: {
            break;
        }
    }
    return ret;
}

static inline uint32_t listen_tcpa_running(tcpa_monitor_t *monitor)
{
    // 判断启动条件
    if (monitor->login_status == RCST_LOGIN) {
        tcpa_ctrl_t *ctrl = NULL;
        list_for_each_entry(ctrl, &monitor->tcpa_ctrl_list, node) {
            if (ctrl->tcpa_cfg.tcpa_enable) {
                
                // 异常状态校验，如果有server_ip未设置的异常，则不启动
                if (tcpa_abnormal_status_check(ctrl, TCPA_ABNORMAL_STATUS_UNSET_SERVER_IP)) {
                    continue;
                }

                // tcpa还没有启动
                if (!tcpa_is_running(ctrl)) {
                    // 如果触发了退避，校验退避时间
                    if (ctrl->backoff.interval && (time(NULL) < ctrl->backoff.last_time + ctrl->backoff.interval)) {
                        continue;
                    }
                    // 启动tcpa
                    if (tcpa_pid_ctrl_util(ctrl) < 0) {
                        // 启动失败，退避重试
                        ctrl->backoff.last_time = time(NULL);
                        int exponent = ctrl->backoff.try_cnt > 5 ? 5 : ctrl->backoff.try_cnt;
                        ctrl->backoff.interval = power_integer( 2, exponent);
                        ctrl->backoff.try_cnt++;
                        TCPAM_LOG_INFO("Failed to start tcpa_util for %s, try again after %u seconds", ctrl->vrf_name, ctrl->backoff.interval)
                        continue;
                    }
                    else { 
                        // 启动成功，重置退避参数
                        TCPAM_LOG_INFO("Started tcpa_util for %s with pid "PRINTF_UINT64_FORMAT"", ctrl->vrf_name, ctrl->tcpa_pid);
                        ctrl->backoff.try_cnt = 0;
                        ctrl->backoff.last_time = 0;
                        ctrl->backoff.interval = 0;
                    }
                }
                // tcpa已经启动，但PID不存在（程序挂掉），表示已经退出 需要再次启动
                else if (!pid_exists_from_td_tunnel_tcp(ctrl->tcpa_pid)) {
                    TCPAM_LOG_WARNING("tcpa_util for %s with pid "PRINTF_UINT64_FORMAT" is not running", ctrl->tcpa_cfg.vrf_name, ctrl->tcpa_pid);
                    if (tcpa_pid_ctrl_util(ctrl) < 0) {
                        TCPAM_LOG_WARNING("Failed to restart tcpa_util for %s", ctrl->tcpa_cfg.vrf_name);
                    }
                    else {
                        TCPAM_LOG_INFO("Restarted tcpa_util for %s with pid "PRINTF_UINT64_FORMAT"", ctrl->tcpa_cfg.vrf_name, ctrl->tcpa_pid);
                    }
                    ctrl->tcpa_restart_cnt++;
                }
            }
            else {
                // 如果tcpa已经在运行，但enable标志为0，则停止
                if (tcpa_is_running(ctrl)) {
                    TCPAM_LOG_INFO("tcpa_util for %s with pid "PRINTF_UINT64_FORMAT" is not enabled, stop it", ctrl->tcpa_cfg.vrf_name, ctrl->tcpa_pid);
                    stop_tcpa_util(ctrl);
                }
            }
        }
    } 

    return 0;
}

static inline void tcpa_cfg_set_default(tcpa_cfg_t *cfg, net_mode_e net_mode)
{
    memset(cfg->vrf_name, 0, sizeof(cfg->vrf_name));
    cfg->vrf_id = 0;
    cfg->tcpa_enable = 0;
    cfg->max_connect = DEFAULT_ACCELERATION_LINK_NUM;
    memset(cfg->server_ip_str, 0, sizeof(cfg->server_ip_str));
    cfg->server_port = DEFAULT_TCPA_SERVER_PORT;
    cfg->listen_port = DEFAULT_LOCAL_LISTEN_PORT;
    cfg->net_mode = net_mode;
}

static inline void tcpa_cfg_set_server_ip(tcpa_cfg_t *cfg, int svn_id, pep_svn_info_t *pep_svn_info)
{
    for (int i = 0; i < pep_svn_info->svn_num; i++) {
        // printf("[%d] svn_id:%d, pep_server_ip:%s\n", i, pep_svn_info->pep_svn[i].svn, pep_svn_info->pep_svn[i].now_pep_server_ip);
        if (pep_svn_info->pep_svn[i].svn == svn_id) {
            strcpy(cfg->server_ip_str, pep_svn_info->pep_svn[i].now_pep_server_ip);
            strcpy(cfg->local_ip_str, pep_svn_info->pep_svn[i].now_svn_ip);
            break;
        }
    }
}

static inline bool vrf_id_is_exist(tcpa_monitor_t *monitor, uint32_t vrf_id)
{
    tcpa_ctrl_t *ctrl = NULL;
    list_for_each_entry(ctrl, &monitor->tcpa_ctrl_list, node) {
        if (ctrl->tcpa_cfg.vrf_id == vrf_id) {
            return true;
        }
    }
    return false;
}

static inline tcpa_ctrl_t *get_tcpa_ctrl_node_by_vrf_id(tcpa_monitor_t *monitor, uint32_t vrf_id)
{
    tcpa_ctrl_t *ctrl = NULL;
    list_for_each_entry(ctrl, &monitor->tcpa_ctrl_list, node) {
        if (ctrl->tcpa_cfg.vrf_id == vrf_id) {
            return ctrl;
        }
    }
    return NULL;
}

static inline void print_tcpa_ctrl_list(tcpa_monitor_t *monitor, void *arg)
{
    tcpa_ctrl_t *pNode = NULL;
    char vrf_list[1024] = {0};
    int offset = 0;
    list_for_each_entry(pNode, &monitor->tcpa_ctrl_list, node) {
        snprintf(vrf_list + offset, sizeof(vrf_list) - offset, "%s ", pNode->tcpa_cfg.vrf_name);
        offset += strlen(pNode->tcpa_cfg.vrf_name) + 1;
        if (offset >= sizeof(vrf_list)) {
            TCPAM_LOG_INFO("%s", vrf_list);
            offset = 0;
        }
    }
    TCPAM_LOG_INFO("%s tcpa_ctrl_list: %s", (char *)arg, vrf_list);
}

static inline void reset_white_list_rule_list(tcpa_monitor_t *monitor)
{
    monitor->rule_node_num = 0;
    // 安全方式遍历，可以删除节点
    rule_cfg_t *pNode = NULL, *pTemp = NULL;
    list_for_each_entry_safe(pNode, pTemp, &monitor->rule_list, node) {
        list_del(&pNode->node);
        memset(pNode, 0, sizeof(rule_cfg_t));
        free(pNode);
    }
    list_head_init(&monitor->rule_list);
    // clean nftables
    call_clean_whitelist_sh(monitor);
}

static inline void whitelist_rule_set_unuse(list_head_t *rule_list)
{
    rule_cfg_t *pNode = NULL;
    list_for_each_entry(pNode, rule_list, node) {
        pNode->in_use = false;
    }
}

static inline int get_svn_ip(pep_svn_info_t *pep_svn_info, int svn_id, char *ip_str, int len) 
{
    for (int i = 0; i < pep_svn_info->svn_num; i++) {
        if (pep_svn_info->pep_svn[i].svn == svn_id) {
            strncpy(ip_str, pep_svn_info->pep_svn[i].now_svn_ip, len);
            ip_str[len] = '\0';
            return 0;
        }
    }
    return -1;
}


#endif /* TCPA_UTIL_H */